/*
 * @Author: shiguo
 * @Date: 2022-04-24 14:27:02
 * @LastEditors: shiguo
 * @LastEditTime: 2023-03-23 15:04:18
 * @FilePath: /@aks-dev/easyui/lib/Hud/Scanner/Scanner.tsx
 */
import React, { useImperativeHandle, useState } from 'react';
import {
    Animated, BackHandler, Easing, Image, StyleProp, StyleSheet, Text, TouchableOpacity, View, ViewStyle
} from 'react-native';
import { RNCamera, BarCodeReadEvent } from 'react-native-camera';
import { PERMISSIONS, requestMultiple } from 'react-native-permissions';
import { navigationBarHeight, px2dp, statusBarHeight } from '../../../screen/px2dp';
import { px2sp } from '../../../screen/px2sp';
import * as utils from '../../../utils/lazy';
import { showToast } from '../Toast/Toast';
import { ScannerOptions } from './index';






// enum SCANNER_TYPE {
//     DENIED = -1,//没有开始权限
//     START = 0,//没有扫描结果，继续扫描
//     SUCCESS = 1,//已有扫描结果，停止扫描
// }

export const Scanner = React.forwardRef<ScannerOptions.RefAttributes, {}>((_, ref) => {
    const [show, setShow] = useState<boolean>(false);
    const [torchOn, setTorchOn] = React.useState<boolean>(false)
    const moveAnim = React.useRef(new Animated.Value(0)).current
    const [pointStyle, setPointStyle] = React.useState<StyleProp<ViewStyle>>()
    const cameraRef: React.MutableRefObject<RNCamera> = React.useRef() as any
    const _cbRef: React.MutableRefObject<ScannerOptions.CallBack> = React.useRef() as any
    const _scanerResultRef = React.useRef<any>()
    React.useEffect(() => {
        const onBackPress = () => {
            if (show) {
                _hideScanner()
            }
            return true
        }
        BackHandler.addEventListener('hardwareBackPress', onBackPress);
        return () => BackHandler.removeEventListener('hardwareBackPress', onBackPress);
    }, [show])




    useImperativeHandle<unknown, ScannerOptions.RefAttributes>(ref, () => ({
        showScanner: _showScanner,
        hideScanner: _hideScanner
    }), [show])



    const _showScanner = async (cb: ScannerOptions.CallBack) => {
        let res = await requestMultiple([PERMISSIONS.IOS.CAMERA, PERMISSIONS.ANDROID.CAMERA])
        if (res[PERMISSIONS.ANDROID.CAMERA] == "granted" || res[PERMISSIONS.IOS.CAMERA] == "granted") {
            _scanerResultRef.current = undefined;
            setShow(true);
            setPointStyle({})
            await utils.sleep()
            animationStart()
            _cbRef.current = cb;
        } else {
            _hideScanner()
            showToast('您未开启相机权限，暂不能使用此功能')
        }


    }

    const _hideScanner = async () => {
        animationStop()
        await utils.sleep()
        setShow(false);
    }



    const animation = Animated.loop(Animated.sequence([
        Animated.timing(
            moveAnim,
            {
                toValue: px2dp(222),
                duration: 3000,
                easing: Easing.linear,
                useNativeDriver: true,
            }
        ),
        Animated.timing(
            moveAnim,
            {
                toValue: 0,
                duration: 3000,
                easing: Easing.linear,
                useNativeDriver: true,
            }
        )
    ]))



    const animationStart = async () => {

        cameraRef.current?.resumePreview()
        animation.start(({ finished }) => {
            // console.log('animationStart finished', finished)
            if (finished) {
                animation.reset()
                animation.start()
            }
        })
    }
    const animationStop = (result?: any) => {
        cameraRef.current?.pausePreview()
        animation.stop()
    }


    // const getPointFromBounds = (bounds) => {
    //     let x = 0
    //     let y = 0

    //     if (Platform.OS == 'android') {
    //         bounds.origin.forEach(i => {
    //             x = Math.max(x, parseFloat(i.x))
    //             y = Math.max(y, parseFloat(i.y))
    //         })

    //         y = y * DeviceHeight / bounds.width
    //         x = x * DeviceWidth / bounds.height
    //     }

    //     if(Platform.OS == 'ios'){
    //         x=parseFloat(bounds.origin.x)
    //         y=parseFloat(bounds.origin.y)
    //     }

    //     return { x, y }
    // }


    const onBarCodeRead = (e: BarCodeReadEvent) => {
        // console.log('ss onBarCodeRead: ', JSON.stringify(e))
        if (e?.data?.length > 0 && _scanerResultRef.current == undefined) {
            _scanerResultRef.current = e?.data
            _cbRef.current(e?.data)
            _hideScanner()
        }
    }







    if (!show) return null;
    return (
        <TouchableOpacity disabled style={StyleSheet.absoluteFillObject}>
            <RNCamera
                ref={cameraRef}
                captureAudio={false}
                autoFocus={RNCamera.Constants.AutoFocus.on}/*自动对焦*/
                style={styles.camera}
                type={RNCamera.Constants.Type.back}/*切换前后摄像头 front前back后*/
                flashMode={torchOn ? RNCamera.Constants.FlashMode.torch : RNCamera.Constants.FlashMode.off}/*相机闪光模式*/
                onBarCodeRead={onBarCodeRead}


            >
                {/* 导航栏 */}
                <View style={{ display: 'flex', justifyContent: "center", alignItems: "center", height: navigationBarHeight, marginTop: statusBarHeight, position: 'relative' }}>
                    <TouchableOpacity onPress={() => _hideScanner()} style={{ height: navigationBarHeight, width: px2dp(50), paddingLeft: px2dp(15), position: 'absolute', left: 0, display: 'flex', justifyContent: 'center' }} >
                        <Image source={require('./icon_back_white.png')} style={{ width: px2dp(20), height: px2dp(20) }} resizeMode='contain' />
                    </TouchableOpacity>
                    <Text style={{ fontSize: px2sp(16), color: 'white', fontWeight: 'bold' }}>扫一扫</Text>
                </View>

                {/* 动画框 */}
                <View style={styles.scanContainer}>
                    <View style={styles.rectangle}>
                        <View style={styles.rectangleLeft} />
                        <View style={styles.cameraBackground}>
                            <Animated.View style={[styles.scanLine, { transform: [{ translateY: moveAnim }] }]} />
                            <View style={styles.reactLineTopLeftX} />
                            <View style={styles.reactLineTopLeftY} />
                            <View style={styles.reactLineTopRightX} />
                            <View style={styles.reactLineTopRightY} />
                            <View style={styles.reactLineBottomLeftX} />
                            <View style={styles.reactLineBottomLeftY} />
                            <View style={styles.reactLineBottomRightX} />
                            <View style={styles.reactLineBottomRightY} />
                        </View>
                        <View style={styles.rectangleRight} />
                    </View>

                    <TouchableOpacity onPress={() => setTorchOn(!torchOn)}>
                        <Image
                            source={torchOn ? require('./flashlight-blue.png') : require('./flashlight-white.png')}
                            style={styles.flashlight} />
                    </TouchableOpacity>
                    <Text style={styles.rectangleText}>将二维码/条码放入框内，即可自动扫描</Text>
                </View>
                <View style={pointStyle} />
            </RNCamera>

        </TouchableOpacity>
    )
})



const transparent = '#00000000'
const lineColor = '#6ab3ff'
const scanW = 225
const scanCornerLineLength = 15;
const scanCornerLineHeight = 3
const styles = StyleSheet.create({
    camera: { display: 'flex', flex: 1, flexDirection: 'column', backgroundColor: "red" },
    cameraBackground: { width: px2dp(scanW), height: px2dp(scanW), backgroundColor: transparent },
    scanContainer: { display: 'flex', flex: 1, justifyContent: 'center', alignItems: 'center' },
    rectangle: { flexDirection: 'row', overflow: 'hidden', },
    rectangleLeft: { backgroundColor: transparent, height: px2dp(scanW), width: px2dp(scanW) },
    rectangleRight: { backgroundColor: transparent, height: px2dp(scanW), width: px2dp(scanW) },
    rectangleText: { color: '#fff', lineHeight: px2dp(15), },
    scanLine: { width: px2dp(scanW), height: px2dp(scanCornerLineHeight), borderRadius: px2dp(25), backgroundColor: lineColor, },
    reactLineTopLeftX: { position: 'absolute', top: 0, left: 0, width: px2dp(scanCornerLineLength), height: px2dp(scanCornerLineHeight), backgroundColor: lineColor },
    reactLineTopLeftY: { position: 'absolute', top: 0, left: 0, width: px2dp(scanCornerLineHeight), height: px2dp(scanCornerLineLength), backgroundColor: lineColor },
    reactLineTopRightX: { position: 'absolute', top: 0, right: 0, width: px2dp(scanCornerLineLength), height: px2dp(scanCornerLineHeight), backgroundColor: lineColor },
    reactLineTopRightY: { position: 'absolute', top: 0, right: 0, width: px2dp(scanCornerLineHeight), height: px2dp(scanCornerLineLength), backgroundColor: lineColor },
    reactLineBottomLeftX: { position: 'absolute', bottom: 0, left: 0, width: px2dp(scanCornerLineLength), height: px2dp(scanCornerLineHeight), backgroundColor: lineColor },
    reactLineBottomLeftY: { position: 'absolute', bottom: 0, left: 0, width: px2dp(scanCornerLineHeight), height: px2dp(scanCornerLineLength), backgroundColor: lineColor },
    reactLineBottomRightX: { position: 'absolute', bottom: 0, right: 0, width: px2dp(scanCornerLineLength), height: px2dp(scanCornerLineHeight), backgroundColor: lineColor },
    reactLineBottomRightY: { position: 'absolute', bottom: 0, right: 0, width: px2dp(scanCornerLineHeight), height: px2dp(scanCornerLineLength), backgroundColor: lineColor },
    flashlight: { width: px2dp(30), height: px2dp(30), resizeMode: 'contain', marginTop: px2dp(50), marginBottom: px2dp(15), marginHorizontal: px2dp(15) },
    grantedText: { lineHeight: px2dp(30), color: lineColor, fontWeight: 'bold' }
})




export const scannerRef = React.createRef<ScannerOptions.RefAttributes>();
export const showScanner = (cb: ScannerOptions.CallBack) => scannerRef.current?.showScanner(cb)
export const hideScanner = () => scannerRef.current?.hideScanner()